/*
//
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//    Copyright (c) 2007 Intel Corporation. All Rights Reserved.
//
//
*/

#include "umc_defs.h"
#if defined(UMC_ENABLE_AVS_VIDEO_DECODER)

#include <trace_log.h>
#include "umc_avs_dec_decompressor.h"
#include "umc_avs_picture_header.h"
#include "umc_avs_mb_info.h"
#include "umc_avs_pic.h"

namespace UMC
{

void AVSDecompressor::ReconstructMotionVectorsBSliceDirect(void)
{
    eAVSDivBlockType divCollBlock;

    divCollBlock = GetCollocatedBlockDivision();

    if (Div_16x16 == divCollBlock)
    {
        // reconstruct the motion vector...
        ReconstructDirectMotionVector(0);

        // ... and clone it
        m_pMbInfo->mv[AVS_FORWARD][1] = m_pMbInfo->mv[AVS_FORWARD][0];
        m_pMbInfo->mv[AVS_FORWARD][2] = m_pMbInfo->mv[AVS_FORWARD][0];
        m_pMbInfo->mv[AVS_FORWARD][3] = m_pMbInfo->mv[AVS_FORWARD][0];
        m_pMbInfo->mv[AVS_BACKWARD][1] = m_pMbInfo->mv[AVS_BACKWARD][0];
        m_pMbInfo->mv[AVS_BACKWARD][2] = m_pMbInfo->mv[AVS_BACKWARD][0];
        m_pMbInfo->mv[AVS_BACKWARD][3] = m_pMbInfo->mv[AVS_BACKWARD][0];

        WRITE_TRACE_LOG(_vec_dir_tst, "direct vectors for block", 1);
        WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][1].vector.x);
        WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][1].vector.y);
        WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][1].vector.x);
        WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][1].vector.y);
        WRITE_TRACE_LOG(_vec_dir_tst, "direct vectors for block", 2);
        WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][2].vector.x);
        WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][2].vector.y);
        WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][2].vector.x);
        WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][2].vector.y);
        WRITE_TRACE_LOG(_vec_dir_tst, "direct vectors for block", 3);
        WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][3].vector.x);
        WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][3].vector.y);
        WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][3].vector.x);
        WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][3].vector.y);
    }
    else if (Div_16x8 == divCollBlock)
    {
        // reconstruct the motion vector...
        ReconstructDirectMotionVector(0);

        // ... and clone it
        m_pMbInfo->mv[AVS_FORWARD][1] = m_pMbInfo->mv[AVS_FORWARD][0];
        m_pMbInfo->mv[AVS_BACKWARD][1] = m_pMbInfo->mv[AVS_BACKWARD][0];

        WRITE_TRACE_LOG(_vec_dir_tst, "direct vectors for block", 1);
        WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][1].vector.x);
        WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][1].vector.y);
        WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][1].vector.x);
        WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][1].vector.y);

        // reconstruct the motion vector...
        ReconstructDirectMotionVector(2);

        // ... and clone it
        m_pMbInfo->mv[AVS_FORWARD][3] = m_pMbInfo->mv[AVS_FORWARD][2];
        m_pMbInfo->mv[AVS_BACKWARD][3] = m_pMbInfo->mv[AVS_BACKWARD][2];

        WRITE_TRACE_LOG(_vec_dir_tst, "direct vectors for block", 3);
        WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][3].vector.x);
        WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][3].vector.y);
        WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][3].vector.x);
        WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][3].vector.y);

        // correct type division type
        m_pMbInfo->divType = Div_16x8;
    }
    else if (Div_8x16 == divCollBlock)
    {
        // reconstruct the motion vector...
        ReconstructDirectMotionVector(0);

        // ... and clone it
        m_pMbInfo->mv[AVS_FORWARD][2] = m_pMbInfo->mv[AVS_FORWARD][0];
        m_pMbInfo->mv[AVS_BACKWARD][2] = m_pMbInfo->mv[AVS_BACKWARD][0];

        // reconstruct the motion vector...
        ReconstructDirectMotionVector(1);

        // ... and clone it
        m_pMbInfo->mv[AVS_FORWARD][3] = m_pMbInfo->mv[AVS_FORWARD][1];
        m_pMbInfo->mv[AVS_BACKWARD][3] = m_pMbInfo->mv[AVS_BACKWARD][1];

        WRITE_TRACE_LOG(_vec_dir_tst, "direct vectors for block", 2);
        WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][2].vector.x);
        WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][2].vector.y);
        WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][2].vector.x);
        WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][2].vector.y);

        WRITE_TRACE_LOG(_vec_dir_tst, "direct vectors for block", 3);
        WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][3].vector.x);
        WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][3].vector.y);
        WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][3].vector.x);
        WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][3].vector.y);

        // correct type division type
        m_pMbInfo->divType = Div_8x16;
    }
    else
    {
        // reconstruct the motion vectors
        ReconstructDirectMotionVector(0);
        ReconstructDirectMotionVector(1);
        ReconstructDirectMotionVector(2);
        ReconstructDirectMotionVector(3);

        // correct type division type
        m_pMbInfo->divType = Div_8x8;
    }

    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][0].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][0].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][1].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][1].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][2].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][2].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][3].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][3].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][0].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][0].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][1].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][1].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][2].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][2].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][3].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][3].vector.y);

} // void AVSDecompressor::ReconstructMotionVectorsBSliceDirect(void)

eAVSDivBlockType AVSDecompressor::GetCollocatedBlockDivision(void)
{
    AVSPicture *pRefBw;

    // get backward reference
    pRefBw = m_pRefs[AVS_BACKWARD][0];

    // the backward reference is a frame coded picture
    if (pRefBw->m_picHeader.picture_structure)
    {
        AVS_MB_INFO *pMbInfo;

        // get collocated block's info
        pMbInfo = pRefBw->m_pMbInfo + MbIndex;

        // if it is an intra MB,
        // then we can process all motion vector at once
        if (I_8x8 == pMbInfo->MbType)
        {
            return Div_16x16;
        }
        else
        {
            return pMbInfo->divType;
        }
    }
    // the backward reference is a field coded picture,
    // we have to adjust variables
    else
    {
        AVS_MB_INFO *pMbInfo;
        Ipp32s corrIndex;

        corrIndex = (((MbIndex / m_decCtx.MbWidth) / 2) * m_decCtx.MbWidth) +
                    (MbIndex % m_decCtx.MbWidth);

        // get collocated block's info
        pMbInfo = pRefBw->m_pMbInfo + corrIndex;

        // if it is an intra MB,
        // then we can process all motion vector at once
        if (I_8x8 == pMbInfo->MbType)
        {
            return Div_16x16;
        }
        else
        {
            // mask only vertical division
            return (eAVSDivBlockType) (pMbInfo->divType & 2);
        }
    }

} // eAVSDivBlockType AVSDecompressor::GetCollocatedBlockDivision(void)

void AVSDecompressor::ReconstructDirectMotionVector(Ipp32s blockNum)
{
    Ipp32s corrBlock, corrIndex;
    AVS_MB_INFO *pMbInfo;
    AVSPicture *pRefBw;

    WRITE_TRACE_LOG(_vec_dir_tst, "direct vectors for block", blockNum);

    // get backward reference
    pRefBw = m_pRefs[AVS_BACKWARD][0];

    // the backward reference is a frame coded picture
    if (pRefBw->m_picHeader.picture_structure)
    {
        corrIndex = MbIndex;
        corrBlock = blockNum;
    }
    // the backward reference is a field coded picture,
    // we have to adjust variables
    else
    {
        corrIndex = (((MbIndex / m_decCtx.MbWidth) / 2) * m_decCtx.MbWidth) +
                    (MbIndex % m_decCtx.MbWidth);
        corrBlock = (((MbIndex / m_decCtx.MbWidth) & 1) << 1) + (blockNum & 1);
    }

    // check the type of a corresponding block in the backward reference picture
    pMbInfo = pRefBw->m_pMbInfo + corrIndex;
    if (I_8x8 == pMbInfo->MbType)
    {
        // we must use the reference picture #1
        m_pMbInfo->refIdx[AVS_FORWARD][blockNum] = 0;
        m_pMbInfo->refIdx[AVS_BACKWARD][blockNum] = 0;

        // calculate the forward motion vector
        GetMotionVectorPredictor16x16(PredForward, blockNum);
        m_pMbInfo->mv[AVS_FORWARD][blockNum] = m_mvPred;

        // calculate the backward motion vector
        GetMotionVectorPredictor16x16(PredBackward, blockNum);
        m_pMbInfo->mv[AVS_BACKWARD][blockNum] = m_mvPred;
    }
    else
    {
        Ipp32s BlockDistanceFw, BlockDistanceBw;
        Ipp32s DistanceIndexFw, DistanceIndexBw;
        Ipp32s BlockDistanceRef;
        Ipp32s DistanceIndexRef;
        Ipp32s DistanceIndexCur;
        AVSMVector mvRef;

        //
        // FIRST STEP
        //

        {
            Ipp32s refIdx;

            // get reference motion vector and distance index
            mvRef = pMbInfo->mv[AVS_FORWARD][corrBlock];
            refIdx = pMbInfo->refIdx[AVS_FORWARD][corrBlock];
            DistanceIndexRef = pRefBw->m_distIdx[AVS_FORWARD][refIdx];

            // get distances
            DistanceIndexFw = m_distIdx[AVS_FORWARD][0];
            DistanceIndexBw = m_distIdx[AVS_BACKWARD][0];

            BlockDistanceFw = m_blockDist[AVS_FORWARD][0];
            BlockDistanceBw = m_blockDist[AVS_BACKWARD][0];

            DistanceIndexCur = m_decCtx.m_pPicHeader->picture_distance * 2;
        }

        //
        // SECOND STEP
        //
        BlockDistanceRef = IPP_MAX(1, (DistanceIndexBw - DistanceIndexRef + 512) % 512);

        BlockDistanceFw = (DistanceIndexCur - DistanceIndexFw + 512) % 512;
        BlockDistanceBw = (DistanceIndexBw - DistanceIndexCur + 512) % 512;

        // but backward reference is a field pair
        if (0 == pRefBw->m_picHeader.picture_structure)
        {
            mvRef.vector.y *= 2;
        }

        //
        // THIRD STEP
        //
        {
            AVSMVector mvFw, mvBw;

            if (0 > mvRef.vector.x)
            {
                mvFw.vector.x = (Ipp16s) -(((16384 / BlockDistanceRef) *
                                            (1 - mvRef.vector.x * BlockDistanceFw) - 1) >> 14);
                mvBw.vector.x = (Ipp16s) (((16384 / BlockDistanceRef) *
                                           (1 - mvRef.vector.x * BlockDistanceBw) - 1) >> 14);
            }
            else
            {
                mvFw.vector.x = (Ipp16s) (((16384 / BlockDistanceRef) *
                                           (1 + mvRef.vector.x * BlockDistanceFw) - 1) >> 14);
                mvBw.vector.x = (Ipp16s) -(((16384 / BlockDistanceRef) *
                                            (1 + mvRef.vector.x * BlockDistanceBw) - 1) >> 14);
            }

            if (0 > mvRef.vector.y)
            {
                mvFw.vector.y = (Ipp16s) -(((16384 / BlockDistanceRef) *
                                            (1 - mvRef.vector.y * BlockDistanceFw) - 1) >> 14);
                mvBw.vector.y = (Ipp16s) (((16384 / BlockDistanceRef) *
                                           (1 - mvRef.vector.y * BlockDistanceBw) - 1) >> 14);
            }
            else
            {
                mvFw.vector.y = (Ipp16s) (((16384 / BlockDistanceRef) *
                                           (1 + mvRef.vector.y * BlockDistanceFw) - 1) >> 14);
                mvBw.vector.y = (Ipp16s) -(((16384 / BlockDistanceRef) *
                                            (1 + mvRef.vector.y * BlockDistanceBw) - 1) >> 14);
            }

            m_pMbInfo->mv[AVS_FORWARD][blockNum] = mvFw;
            m_pMbInfo->mv[AVS_BACKWARD][blockNum] = mvBw;
        }
    }

    // set the prediction type
    m_pMbInfo->predType[blockNum] = PredBiDir;

    WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][blockNum].vector.x);
    WRITE_TRACE_LOG(_vec_dir_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][blockNum].vector.y);
    WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][blockNum].vector.x);
    WRITE_TRACE_LOG(_vec_dir_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][blockNum].vector.y);

} // void AVSDecompressor::ReconstructDirectMotionVector(Ipp32s blockNum)

} // namespace UMC

#endif // defined(UMC_ENABLE_AVS_VIDEO_DECODER)
